﻿using System;
using System.IO;
using System.Net;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Text;

using Codice.Utils;
using log4net;

using Redmine.Net.Api;
using Redmine.Net.Api.Types;

using Codice.Client.Extension.Types;

namespace Codice.Client.Extension
{
    public class RedmineExtension : BasePlasticExtension
    {
        protected RedmineExtensionMultipleConfiguration mConfig;

        public static string ConfigFileName = "redmineextension.conf";

        private static readonly string ExtensionName = "Redmine Extension";

        private static readonly string AttributePrefix = "redmine";
        
        private static readonly ILog mLog = LogManager.GetLogger("extensions");
        

        public RedmineExtension()
        {
            mConfig = new RedmineExtensionMultipleConfiguration();

            // Load config from disk
            bool bSuccess = LoadConfig(ConfigFileName);
            UpdateBaseConfig(bSuccess);
        }

        private bool LoadConfig(string configFile)
        {
            bool bSuccess;
            mConfig = (RedmineExtensionMultipleConfiguration)ExtensionServices.LoadConfig(ConfigFileName, typeof(RedmineExtensionMultipleConfiguration), out bSuccess);
            return bSuccess;
        }

        private void UpdateBaseConfig(bool fromConfigFile)
        {
            if (fromConfigFile)
            {
                mBaseConfig = mConfig.ConfigurationEntries[0];
                mBaseConfig.WorkingMode = mConfig.WorkingMode;
            }
            //if don't have the multiple configuration file, use the standard
            else
            {
                RedmineExtensionConfiguration config = (RedmineExtensionConfiguration)ExtensionServices.LoadConfig(ConfigFileName, typeof(RedmineExtensionConfiguration));
                mBaseConfig = config;
                mConfig = new RedmineExtensionMultipleConfiguration();
                mConfig.ConfigurationEntries[0] = config;
            }
            mBaseConfig.SetDefaultAttributePrefix(AttributePrefix);
        }

        #region Members of IPlasticExtension

        public override string GetName()
        {
            return ExtensionName;
        }

        #endregion

        #region Members of ITaskProvider

        public override PlasticTask[] LoadTask(string[] id, string repName)
        {
            if (id == null)
                return null;

            PlasticTask[] result = new PlasticTask[id.Length];

            var manager = CreateRedmineManager(repName);
            if (manager == null)
                return null;
            
            for (int i = 0; i < id.Length; i++)
            {
                try
                {
                    string strId = id[i];
                    if (strId == null)
                    {
                        continue;
                    }

                    var issue = manager.GetObject<Issue>(strId, null);

                    RedmineTask task = new RedmineTask(issue, repName);
                    result[i] = task;
                }
                catch (Exception ex)
                {
                    mLog.Error(
                        string.Format("Redmine, error loading tickets: {0}", ex.Message));
                }

            }
            return result;
        }

        private RedmineManager CreateRedmineManager(string repName)
        {
            string host = mConfig.GetUrl(repName);
            string apikey = mConfig.GetApiKey(repName);
            if (apikey == null || apikey == String.Empty)
            {
                string user = mConfig.GetUser(repName);
                string password = CryptoServices.GetDecryptedPassword(mConfig.GetPassword(repName));

                return new RedmineManager(host, user, password);
            }

            return new RedmineManager(host, apikey);
        }

        public override void OpenTask(string id, string repName)
        {
            string url = string.Format(mConfig.GetShowIssueUrl(repName) + mConfig.GetIssueWeb(repName), id);
            System.Diagnostics.Process.Start(url);
        }

        #endregion

        public override string GetBranchPrefix(string repName)
        {
            return mConfig.GetBranchPrefix(repName);
        }

        #region Members of ITaskOnBranch

        public override PlasticTaskConfiguration[] GetTaskConfiguration(string task)
        {
            if (mConfig == null)
            {
                throw new CmExtensionException("EXTENSION_INVALID_CONF");
            }

            long taskId;
            try
            {
                taskId = long.Parse(task);
            }
            catch
            {
                throw new CmExtensionException("INVALID_TASK", task);
            }


            PlasticTaskConfiguration[] taskConfig = CreateTaskConfiguration(taskId);
            return taskConfig;
        }

        #endregion

        private PlasticTaskConfiguration[] CreateTaskConfiguration(long taskId)
        {
            ArrayList result = new ArrayList();
            foreach (RedmineExtensionConfiguration entry in mConfig.ConfigurationEntries)
            {
                PlasticTaskConfiguration taskConf = new PlasticTaskConfiguration();
                taskConf.PlasticPrefix = entry.BranchPrefix;
                taskConf.TaskId = taskId;
                taskConf.ReposiotyName = entry.RepositoryName;
                result.Add(taskConf);
            }

            return (PlasticTaskConfiguration[])result.ToArray(typeof(PlasticTaskConfiguration));
        }
    }
}
